package com.lancoo.ccas53.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lancoo.ccas53.entity.*;
import com.lancoo.ccas53.exception.BizException;
import com.lancoo.ccas53.mapper.*;
import com.lancoo.ccas53.pojo.common.PageInfo;
import com.lancoo.ccas53.pojo.common.ProhibitType;
import com.lancoo.ccas53.pojo.dto.TeacherDto;
import com.lancoo.ccas53.pojo.vo.*;
import com.lancoo.ccas53.service.*;
import com.lancoo.ccas53.util.ExcelFormatUtil;
import com.lancoo.ccas53.util.PagingUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 日期禁排 服务实现类
 * </p>
 *
 * @author quin.song
 * @since 2024-05-20
 */
@Service
public class RuleTimeProhibitServiceImpl extends ServiceImpl<RuleTimeProhibitMapper, RuleTimeProhibit> implements RuleTimeProhibitService {

    @Resource
    private RoomService roomService;
    @Resource
    private TeacherService teacherService;
    @Resource
    private TeachingClassWeekMapper teachingClassWeekMapper;
    @Resource
    private RoomMapper roomMapper;
    @Resource
    private TaskInfoService taskInfoService;
    @Resource
    private RuleUsableService ruleUsableService;
    @Resource
    private TeachingClassService teachingClassService;
    @Resource
    private TeachingClassMapper teachingClassMapper;
    @Resource
    private TeacherMapper teacherMapper;
    @Resource
    private ScheduleService scheduleService;
    @Resource
    private TeachingClassWeekService teachingClassWeekService;
    @Resource
    private CourseService courseService;


    @Override
    public List<RuleTimeProhibit> getTimeProhibit(Integer taskId, Integer optionType, Long optionId, Integer hourType) {
        List<RuleTimeProhibit> timeProhibits = this.lambdaQuery()
                .eq(RuleTimeProhibit::getTaskId, taskId)
                .eq(RuleTimeProhibit::getOptionType, optionType)
                .eq(ObjUtil.isNotNull(optionId), RuleTimeProhibit::getOptionId, optionId)
                .eq(optionType == ProhibitType.TEACHINGCLASS.getCode()
                        && ObjUtil.isNotNull(hourType), RuleTimeProhibit::getHourType, hourType)
                .list();
        return timeProhibits;

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean setTimeProhibit(Integer taskId, Integer optionType, String optionIds, List<RuleTimeProhibit> ruleTimeProhibits) {

        List<Long> ids = new ArrayList<>();
        if (optionType != 1 && StrUtil.isNotEmpty(optionIds)) {
            ids = Arrays.stream(optionIds.split(",")).map(Long::valueOf).collect(Collectors.toList());
        }
//        if (CollUtil.isEmpty(ruleTimeProhibits)){
//            throw new BizException("参数不合法");
//        }
        //删除原有的禁排规则
        this.lambdaUpdate()
                .eq(RuleTimeProhibit::getTaskId, taskId)
                .eq(RuleTimeProhibit::getOptionType, optionType)
                .in(optionType != 1 && CollUtil.isNotEmpty(ids),
                        RuleTimeProhibit::getOptionId, ids)
                .remove();

        //保存新地禁排规则
        List<RuleTimeProhibit> saveList = new ArrayList<>();
        if (CollUtil.isEmpty(ids)) {
            saveList.addAll(ruleTimeProhibits);
        } else {
            for (Long optionId : ids) {
                List<RuleTimeProhibit> temp = JSON.parseArray(JSON.toJSONString(ruleTimeProhibits), RuleTimeProhibit.class);
                temp.forEach(o -> o.setOptionId(optionId));
                saveList.addAll(temp);
            }
        }
        this.saveBatch(saveList);
        if (optionType == ProhibitType.ROOM.getCode()) {
            if (CollUtil.isNotEmpty(saveList)) {
                roomService.lambdaUpdate()
                        .eq(Room::getTaskId, taskId)
                        .in(optionType != 1 && CollUtil.isNotEmpty(ids),
                                Room::getRoomId, ids)
                        .set(Room::getRuleSet, 1)
                        .update();
            } else {
                roomService.lambdaUpdate()
                        .eq(Room::getTaskId, taskId)
                        .in(optionType != 1 && CollUtil.isNotEmpty(ids),
                                Room::getRoomId, ids)
                        .set(Room::getRuleSet, 2)
                        .update();
            }
        } else if (optionType == ProhibitType.TEACHER.getCode()) {
            if (CollUtil.isNotEmpty(saveList)) {
                teacherService.lambdaUpdate()
                        .eq(Teacher::getTaskId, taskId)
                        .in(optionType != 1 && CollUtil.isNotEmpty(ids),
                                Teacher::getTeacherId, ids)
                        .set(Teacher::getRuleSet, 1)
                        .update();
            } else {
                teacherService.lambdaUpdate()
                        .eq(Teacher::getTaskId, taskId)
                        .in(optionType != 1 && CollUtil.isNotEmpty(ids),
                                Teacher::getTeacherId, ids)
                        .set(Teacher::getRuleSet, 2)
                        .update();
            }
        }
        return true;
    }

    @Override
    public PageInfo<RoomWithRuleVo> getRoomListWithRule(Integer taskId, Integer campusId, Integer buildingId,
                                                        Integer floor, Integer roomType, String keyword, String baseCollegeId, Integer dataRange,
                                                        Integer currentPage, Integer pageSize) {
        IPage<RoomWithRuleVo> page = new Page(currentPage, pageSize);
        IPage<RoomWithRuleVo> roomPage = roomMapper.getRoomListWithRule(page, taskId, campusId, buildingId, floor, roomType, keyword, baseCollegeId, dataRange);

        List<RoomWithRuleVo> rooms = roomPage.getRecords();

        if (CollUtil.isNotEmpty(rooms)) {
            List<Long> roomIds = rooms.stream()
                    .map(Room::getRoomId).distinct()
                    .collect(Collectors.toList());

            List<RuleTimeProhibit> ruleList = this.lambdaQuery().eq(RuleTimeProhibit::getTaskId, taskId)
                    .eq(RuleTimeProhibit::getOptionType, ProhibitType.ROOM.getCode())
                    .in(RuleTimeProhibit::getOptionId, roomIds)
                    .list();

            if (CollUtil.isNotEmpty(ruleList)) {
                Map<Long, List<RuleTimeProhibit>> map = ruleList.stream()
                        .collect(Collectors.groupingBy(RuleTimeProhibit::getOptionId));
                TaskInfo taskInfo = taskInfoService.lambdaQuery().eq(TaskInfo::getTaskId, taskId).one();
                rooms.forEach(o -> {
                    List<RuleTimeProhibit> rules = map.getOrDefault(o.getRoomId(), new ArrayList<>());
                    o.setRuleTimeProhibitList(rules);
                    if (CollUtil.isNotEmpty(rules)) {
                        List<String> timeCodes = rules.stream().map(RuleTimeProhibit::getTimeCode).distinct().collect(Collectors.toList());
                        o.setTimeCodes(ExcelFormatUtil.getTimeCodeFormat(taskInfo.getCycleDay(), timeCodes));
                    }

                });
            }
            roomPage.setRecords(rooms);
        }


        return PagingUtil.formatPageResult(roomPage);
    }

    @Override
    public PageInfo<TeachingClassWithRuleVo> getTeachingClassListWithRule(Integer taskId, String baseCollegeId, String courseTypeId, Integer courseNature, String keyword, Integer dataRange, Integer currentPage, Integer pageSize) {
        IPage<TeachingClassWithRuleVo> page = new Page(currentPage, pageSize);
        IPage<TeachingClassWithRuleVo> teachingClassPage = baseMapper.getTeachingClassListWithRule(page, taskId, baseCollegeId, courseTypeId, courseNature, keyword, dataRange);

        List<TeachingClassWithRuleVo> teachingClassList = teachingClassPage.getRecords();

        if (CollUtil.isNotEmpty(teachingClassList)) {
            List<Long> teachingClassIds = teachingClassList.stream()
                    .map(TeachingClassWithRuleVo::getTeachingClassId)
                    .distinct().collect(Collectors.toList());

            Map<Long, List<TeacherDto>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(teachingClassIds)
                    .stream().collect(Collectors.groupingBy(TeacherDto::getTeachingClassId));


            List<RuleTimeProhibit> ruleList = this.lambdaQuery().eq(RuleTimeProhibit::getTaskId, taskId)
                    .eq(RuleTimeProhibit::getOptionType, ProhibitType.TEACHINGCLASS.getCode())
                    .in(RuleTimeProhibit::getOptionId, teachingClassIds)
                    .list();
            Map<Long, List<RuleTimeProhibit>> ruleMap = ruleList.stream()
                    .collect(Collectors.groupingBy(RuleTimeProhibit::getOptionId));

            TaskInfo taskInfo = taskInfoService.lambdaQuery().eq(TaskInfo::getTaskId, taskId).one();
            teachingClassList.forEach(a -> {
                List<TeacherDto> teachers = teachingClassToTeacher.getOrDefault(a.getTeachingClassId(), new ArrayList<>());
                teachers = teachers.stream().filter(t -> Objects.equals(t.getHourType(), a.getHourType())).collect(Collectors.toList());
                a.setTeachingClassTeachers(teachers);

                //规则
                List<RuleTimeProhibit> rules = ruleMap.getOrDefault(a.getTeachingClassId(), new ArrayList<>());
                rules = rules.stream().filter(r -> Objects.equals(r.getHourType(), a.getHourType())).collect(Collectors.toList());
                a.setRuleTimeProhibitList(rules);
                if (CollUtil.isNotEmpty(rules)) {
                    a.setForbbidenTimecode(ExcelFormatUtil.getTimeCodeFormat(taskInfo.getCycleDay(), rules.stream()
                            .filter(o -> o.getFlag() == 1)
                            .map(RuleTimeProhibit::getTimeCode).distinct()
                            .collect(Collectors.toList())));
                    a.setPriorityTimecode(ExcelFormatUtil.getTimeCodeFormat(taskInfo.getCycleDay(), rules.stream()
                            .filter(o -> o.getFlag() == 2)
                            .map(RuleTimeProhibit::getTimeCode).distinct()
                            .collect(Collectors.toList())));
                }
            });

            teachingClassPage.setRecords(teachingClassList);
        }


        return PagingUtil.formatPageResult(teachingClassPage);
    }

    @Override
    public void clearProhibit(Integer taskId, Integer optionType, List<Long> optionIds, boolean all) {
        all = optionType == 1 || all;
        this.lambdaUpdate().eq(RuleTimeProhibit::getTaskId, taskId)
                .eq(RuleTimeProhibit::getOptionType, optionType)
                .in(CollUtil.isNotEmpty(optionIds) && !all,
                        RuleTimeProhibit::getOptionId, optionIds)
                .remove();
        if (optionType == ProhibitType.ROOM.getCode()) {
            roomService.lambdaUpdate()
                    .eq(Room::getTaskId, taskId)
                    .in(optionType != 1 && CollUtil.isNotEmpty(optionIds),
                            Room::getRoomId, optionIds)
                    .set(Room::getRuleSet, 2)
                    .update();
        } else if (optionType == ProhibitType.TEACHER.getCode()) {
            teacherService.lambdaUpdate()
                    .eq(Teacher::getTaskId, taskId)
                    .in(optionType != 1 && CollUtil.isNotEmpty(optionIds),
                            Teacher::getTeacherId, optionIds)
                    .set(Teacher::getRuleSet, 2)
                    .update();
        }
    }

    @Override
    public RuleStatic getRoomRuleStatic(Integer taskId, Integer campusId, Integer buildingId, Integer floor, Integer roomType, String keyword, String baseCollegeId, Integer dataRange, Integer currentPage, Integer pageSize) {
        IPage<Room> page = new Page(currentPage, pageSize);
//        IPage<Room> res = roomService.lambdaQuery().eq(Room::getTaskId, taskId)
//                .eq(campusId != null, Room::getCampusId, campusId)
//                .eq(buildingId != null, Room::getBuildingId, buildingId)
//                .eq(floor != null, Room::getBuildingFloor, floor)
//                .eq(roomType != null, Room::getRoomType, roomType)
//                .and(StrUtil.isNotEmpty(keyword), w ->
//                        w.like(Room::getRoomName, keyword)
//                                .or()
//                                .like(Room::getBuildingName, keyword))
//                .page(page);
//        List<Room> list = res.getRecords();
        List<Room> list = roomService.lambdaQuery().eq(Room::getTaskId, taskId)
                .eq(campusId != null, Room::getCampusId, campusId)
                .eq(StrUtil.isNotEmpty(baseCollegeId), Room::getBaseCollegeId, baseCollegeId)
                .eq(buildingId != null, Room::getBuildingId, buildingId)
                .eq(floor != null, Room::getBuildingFloor, floor)
                .eq(roomType != null, Room::getRoomType, roomType)
                .and(StrUtil.isNotEmpty(keyword), w ->
                        w.like(Room::getRoomName, keyword)
                                .or()
                                .like(Room::getBuildingName, keyword))
                .list();
        List<Long> all = list.stream().map(Room::getRoomId).distinct().collect(Collectors.toList());
//        List<Long> roomIds = baseMapper.getTypeRuleSet(taskId,OptionType.ROOM.getCode());
//        roomIds = roomIds.stream().filter(all::contains).collect(Collectors.toList());

        List<Long> roomIds = list.stream().filter(o -> o.getRuleSet() == 1).map(Room::getRoomId).collect(Collectors.toList());

//        HashSet<String> strIds = roomIds.stream().map(String::valueOf)
//                .distinct()
//                .collect(Collectors.toCollection(HashSet::new));

//        if (dataRange == 0){
        return new RuleStatic((long) all.size(), (long) roomIds.size());
//        } else if (dataRange == 1) {
//            return new RuleStatic((long) roomIds.size(), (long) roomIds.size());
//        }else {
//            return new RuleStatic((long) (all.size() - roomIds.size()), (long) (all.size() - roomIds.size()));
//        }
    }

    @Override
    public RuleStatic getTeachingClassRuleStatic(Integer taskId, String baseCollegeId, String courseTypeId, Integer courseNature, String keyword, Integer dataRange, Integer currentPage, Integer pageSize) {
//        IPage<TeachingClassWithRuleVo> page = baseMapper.getTeachingClassListWithRule(new Page<>(currentPage, pageSize), taskId, baseCollageId, courseTypeId, courseNature, keyword,0);
//        List<TeachingClassWithRuleVo> list = page.getRecords();
        List<TeachingClassWithRuleVo> list = baseMapper.getTeachingClassListWithRuleList(taskId, baseCollegeId, courseTypeId, courseNature, keyword, 0);

//        List<RuleTimeProhibit> rules = this.lambdaQuery().eq(RuleTimeProhibit::getTaskId, taskId)
//                .eq(RuleTimeProhibit::getOptionType, OptionType.TEACHINGCLASS.getCode()).list();
//        if (CollUtil.isEmpty(rules)){
//            return new RuleStatic(all, 0L);
//        }

//        List<Long> ids = list.stream().map(TeachingClassWithRuleVo::getTeachingClassId)
//                .distinct()
//                .collect(Collectors.toList());
//        rules = rules.stream().filter(o -> ids.contains(o.getOptionId())).collect(Collectors.toList());

        List<TeachingClassWithRuleVo> setUp = list.stream()
                .filter(o -> o.getRuleSet() == 1).collect(Collectors.toList());

//        Set<String> set = new HashSet<>();
//        setUp.forEach(o -> set.add(o.getTeachingClassId() + "-" + o.getHourType()));


//        if (dataRange == 0){
        return new RuleStatic((long) list.size(), (long) setUp.size());
//        } else if (dataRange == 1) {
//            return new RuleStatic((long) setUp.size(), (long) setUp.size());
//        }else {
//            return new RuleStatic((long) (list.size() - setUp.size()), (long) (list.size() - setUp.size()));
//        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean setTeachingClassProhibit(Integer taskId, Integer optionType, List<TeachingClassWithRuleVo> teachingClass, List<RuleTimeProhibit> ruleTimeProhibits) {
        if (CollUtil.isEmpty(ruleTimeProhibits) || optionType == null || optionType != ProhibitType.TEACHINGCLASS.getCode()) {
            throw new BizException("参数不合法");
        }
        //删除原有的禁排规则
        baseMapper.removeTeachingClassRule(taskId, optionType, teachingClass);

        //保存新地禁排规则
        List<RuleTimeProhibit> saveList = new ArrayList<>();

        for (TeachingClassWithRuleVo aClass : teachingClass) {
            List<RuleTimeProhibit> temp = JSON.parseArray(JSON.toJSONString(ruleTimeProhibits), RuleTimeProhibit.class);
            temp.forEach(o -> {
                o.setOptionId(aClass.getTeachingClassId());
                o.setHourType(aClass.getHourType());
                o.setOptionType(optionType);
                o.setId(null);
            });
            saveList.addAll(temp);
        }

        if (CollUtil.isNotEmpty(saveList)) {
            this.saveBatch(saveList);
            teachingClassWeekMapper.updateRuleSet(taskId, teachingClass, 1);
        } else {
            teachingClassWeekMapper.updateRuleSet(taskId, teachingClass, 2);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void clearTeachingClassProhibit(Integer taskId, Integer optionType, List<TeachingClassWithRuleVo> teachingClassList) {
        //删除原有的禁排规则
        baseMapper.removeTeachingClassRule(taskId, optionType, teachingClassList);
        teachingClassWeekMapper.updateRuleSet(taskId, teachingClassList, 2);
    }

    @Override
    public PageInfo<TeacherWithRuleVo> getTeacherListWithRule(Integer taskId, String baseCollegeId, String keyword, Integer dataRange, Integer currentPage, Integer pageSize) {
        IPage<TeacherWithRuleVo> page = new Page(currentPage, pageSize);
        IPage<TeacherWithRuleVo> teacherPage = baseMapper.getTeacherCourseString(page, taskId, baseCollegeId, keyword, dataRange);

        List<TeacherWithRuleVo> teacherList = teacherPage.getRecords();

        if (CollUtil.isNotEmpty(teacherList)) {
            List<Long> teacherIds = teacherList.stream()
                    .map(TeacherWithRuleVo::getTeacherId)
                    .distinct().collect(Collectors.toList());


            List<RuleTimeProhibit> ruleList = this.lambdaQuery().eq(RuleTimeProhibit::getTaskId, taskId)
                    .eq(RuleTimeProhibit::getOptionType, ProhibitType.TEACHER.getCode())
                    .in(RuleTimeProhibit::getOptionId, teacherIds)
                    .list();
            Map<Long, List<RuleTimeProhibit>> ruleMap = ruleList.stream()
                    .collect(Collectors.groupingBy(RuleTimeProhibit::getOptionId));
            TaskInfo taskInfo = taskInfoService.lambdaQuery().eq(TaskInfo::getTaskId, taskId).one();
            teacherList.forEach(a -> {
                List<RuleTimeProhibit> rules = ruleMap.getOrDefault(a.getTeacherId(), new ArrayList<>());
                a.setRuleTimeProhibitList(rules);
                if (CollUtil.isNotEmpty(rules)) {
                    a.setForbbidenTimecode(ExcelFormatUtil.getTimeCodeFormat(taskInfo.getCycleDay(), rules.stream()
                            .filter(o -> o.getFlag() == 1)
                            .map(RuleTimeProhibit::getTimeCode).distinct()
                            .collect(Collectors.toList())));
                    a.setPriorityTimecode(ExcelFormatUtil.getTimeCodeFormat(taskInfo.getCycleDay(), rules.stream()
                            .filter(o -> o.getFlag() == 2)
                            .map(RuleTimeProhibit::getTimeCode).distinct()
                            .collect(Collectors.toList())));
                }
            });

            teacherPage.setRecords(teacherList);
        }


        return PagingUtil.formatPageResult(teacherPage);
    }

    @Override
    public RuleStatic getTeacherRuleStatic(Integer taskId, String baseCollegeId, String keyword, Integer dataRange, Integer currentPage, Integer pageSize) {
//        IPage<Teacher> page = new Page(currentPage, pageSize);
//        IPage<Teacher> res = teacherService.lambdaQuery().eq(Teacher::getTaskId, taskId)
//                .eq(StrUtil.isNotEmpty(baseCollageId), Teacher::getBaseCollegeId, baseCollageId)
//                .eq(StrUtil.isNotEmpty(keyword), Teacher::getTeacherName, keyword)
//                .page(page);

//        List<Teacher> list = res.getRecords();
        List<Teacher> list = teacherService.lambdaQuery().eq(Teacher::getTaskId, taskId)
                .eq(StrUtil.isNotEmpty(baseCollegeId), Teacher::getBaseCollegeId, baseCollegeId)
                .eq(StrUtil.isNotEmpty(keyword), Teacher::getTeacherName, keyword)
                .list();

        List<Long> all = list.stream().map(Teacher::getTeacherId)
                .distinct().collect(Collectors.toList());

//        List<Long> teacherIds = baseMapper.getTypeRuleSet(taskId,OptionType.TEACHER.getCode());
//        teacherIds = teacherIds.stream().filter(all::contains).collect(Collectors.toList());

        List<Long> setUp = list.stream().filter(o -> o.getRuleSet() == 1).map(Teacher::getTeacherId).collect(Collectors.toList());

//        HashSet<String> strIds = setUp.stream().map(String::valueOf)
//                .distinct()
//                .collect(Collectors.toCollection(HashSet::new));

//        if (dataRange == 0){
        return new RuleStatic((long) all.size(), (long) setUp.size());
//        } else if (dataRange == 1) {
//            return new RuleStatic((long) setUp.size(), (long) setUp.size());
//        }else {
//            return new RuleStatic((long) (all.size() - setUp.size()), (long) (all.size() - setUp.size()));
//        }
    }

    @Override
    public void setCourseLimit(Integer taskId, CourseLimitSetVo vo) {
        if (CollUtil.isNotEmpty(vo.getCourseIds()) && vo.getLimit() != null) {
            courseService.lambdaUpdate()
                    .eq(Course::getTaskId, taskId)
                    .in(Course::getCourseId, vo.getCourseIds())
                    .set(Course::getCourseLimit, vo.getLimit())
                    .update();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void clear(Integer taskId, String baseCollegeId) {
        if (StrUtil.isNotEmpty(baseCollegeId)) {
            List<Long> teachingClasses = teachingClassService.lambdaQuery()
                    .eq(TeachingClass::getTaskId, taskId)
                    .eq(TeachingClass::getBaseCollegeId, baseCollegeId)
                    .list().stream().map(TeachingClass::getTeachingClassId)
                    .collect(Collectors.toList());
            if (CollUtil.isNotEmpty(teachingClasses)) {
                //课程
                this.lambdaUpdate().eq(RuleTimeProhibit::getTaskId, taskId)
                        .eq(RuleTimeProhibit::getOptionType, ProhibitType.TEACHINGCLASS.getCode())
                        .in(RuleTimeProhibit::getOptionId, teachingClasses).remove();
                teachingClassWeekService.lambdaUpdate()
                        .in(TeachingClassWeek::getTeachingClassId, teachingClasses)
                        .set(TeachingClassWeek::getRuleSet, 2)
                        .update();
            }
            List<Long> teachers = teacherService.lambdaQuery()
                    .eq(Teacher::getTaskId, taskId)
                    .eq(Teacher::getBaseCollegeId, baseCollegeId)
                    .list().stream().map(Teacher::getTeacherId)
                    .collect(Collectors.toList());
            if (CollUtil.isNotEmpty(teachers)) {
                //教师
                this.lambdaUpdate().eq(RuleTimeProhibit::getTaskId, taskId)
                        .eq(RuleTimeProhibit::getOptionType, ProhibitType.TEACHER.getCode())
                        .in(RuleTimeProhibit::getOptionId, teachers).remove();
                teacherService.lambdaUpdate()
                        .eq(Teacher::getTaskId, taskId)
                        .in(Teacher::getTeacherId, teachers)
                        .set(Teacher::getRuleSet, 2)
                        .update();
            }
            List<Long> courseIds = courseService.lambdaQuery()
                    .eq(Course::getTaskId, taskId)
                    .eq(Course::getBaseCollegeId, baseCollegeId)
                    .list().stream().map(Course::getCourseId)
                    .distinct().collect(Collectors.toList());
            if (CollUtil.isNotEmpty(courseIds)) {
                courseService.lambdaUpdate()
                        .set(Course::getCourseLimit, 0)
                        .in(Course::getCourseId, courseIds)
                        .update();
            }
        } else {
//            //基础信息
            ruleUsableService.lambdaUpdate().eq(RuleUsable::getTaskId, taskId).remove();
            List<RuleUsable> list = new ArrayList<>();
            if (CollUtil.isEmpty(list)) {
                list = ruleUsableService.initBaseRule(taskId);
            }
            ruleUsableService.saveBatch(list);

            //场地 教师 课程
            this.lambdaUpdate().eq(RuleTimeProhibit::getTaskId, taskId)
                    .ne(RuleTimeProhibit::getOptionType, ProhibitType.TIME.getCode()).remove();
            roomService.lambdaUpdate()
                    .eq(Room::getTaskId, taskId)
                    .set(Room::getRuleSet, 2)
                    .update();
            List<Long> tcIds = teachingClassService.lambdaQuery()
                    .eq(TeachingClass::getTaskId, taskId)
                    .list().stream().map(TeachingClass::getTeachingClassId)
                    .distinct().collect(Collectors.toList());
            if (CollUtil.isNotEmpty(tcIds)) {
                teachingClassWeekService.lambdaUpdate()
                        .in(TeachingClassWeek::getTeachingClassId, tcIds)
                        .set(TeachingClassWeek::getRuleSet, 2)
                        .update();
            }
            teacherService.lambdaUpdate()
                    .eq(Teacher::getTaskId, taskId)
                    .set(Teacher::getRuleSet, 2)
                    .update();
            courseService.lambdaUpdate()
                    .eq(Course::getTaskId, taskId)
                    .set(Course::getCourseLimit, 0)
                    .update();
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void copy(Integer taskId, String schoolId, String term, String baseCollegeId) {
        String year = term.substring(0, term.length() - 2);
        String part = term.substring(term.length() - 2);
        if ("02".equals(part)) {
            term = year + "01";
        } else {
            String[] split = year.split("-");
            term = (Integer.parseInt(split[0]) - 1) + "-" + (Integer.parseInt(split[1]) - 1) + "02";
        }
        TaskInfo taskInfo = taskInfoService.lambdaQuery().eq(TaskInfo::getSchoolId, schoolId).eq(TaskInfo::getTerm, term).one();
        if (taskInfo == null) {
            throw new BizException("上学期不存在计划");
        }

        if (StrUtil.isNotEmpty(baseCollegeId)) {
            List<Teacher> teachers = teacherService.lambdaQuery()
                    .eq(Teacher::getTaskId, taskId)
                    .eq(Teacher::getBaseCollegeId, baseCollegeId)
                    .list();
            if (CollUtil.isNotEmpty(teachers)) {
                //教师
                List<RuleTimeProhibit> teacherRule = baseMapper.getTeacherRule(taskInfo.getTaskId(), ProhibitType.TEACHER.getCode());
                Map<String, Long> teacherMap = teachers.stream()
                        .collect(Collectors.toMap(Teacher::getBaseTeacherId, Teacher::getTeacherId));
                List<RuleTimeProhibit> saveList = teacherRule.stream().peek(o -> {
                    if (teacherMap.containsKey(o.getBaseTeacherId())) {
                        o.setTaskId(taskId);
                        o.setOptionId(teacherMap.get(o.getBaseTeacherId()));
                    }
                }).filter(o -> o.getTaskId() != null).collect(Collectors.toList());

                this.lambdaUpdate().eq(RuleTimeProhibit::getTaskId, taskId)
                        .eq(RuleTimeProhibit::getOptionType, ProhibitType.TEACHER.getCode())
                        .in(RuleTimeProhibit::getOptionId,
                                teachers.stream().map(Teacher::getTeacherId).collect(Collectors.toList()))
                        .remove();
                if (CollUtil.isNotEmpty(saveList)) {
                    teacherService.lambdaUpdate().eq(Teacher::getTaskId, taskId).set(Teacher::getRuleSet, 2).update();
                    baseMapper.addBatch(saveList);
                    teacherService.lambdaUpdate()
                            .eq(Teacher::getTaskId, taskId)
                            .in(Teacher::getTeacherId, saveList.stream().map(RuleTimeProhibit::getOptionId).distinct().collect(Collectors.toList()))
                            .set(Teacher::getRuleSet, 1).update();
                }

            }

            List<Course> courses = courseService.lambdaQuery()
                    .eq(Course::getTaskId, taskId)
                    .eq(Course::getBaseCollegeId, baseCollegeId)
                    .list();
            if (CollUtil.isNotEmpty(courses)) {
                List<String> baseCourseIds = courses.stream().map(Course::getBaseCourseId).distinct().collect(Collectors.toList());
                List<Course> preCourse = courseService.lambdaQuery()
                        .eq(Course::getTaskId, taskInfo.getTaskId())
                        .in(Course::getBaseCourseId, baseCourseIds)
                        .list();
                courseService.lambdaUpdate()
                        .eq(Course::getTaskId, taskId)
                        .eq(Course::getBaseCollegeId, baseCollegeId)
                        .set(Course::getCourseLimit, 0)
                        .update();
                courseService.copyCourseLimit(taskId, preCourse);
            }
        } else {
            //基础信息
            ruleUsableService.lambdaUpdate().eq(RuleUsable::getTaskId, taskId).remove();
            List<RuleUsable> list = ruleUsableService.lambdaQuery().eq(RuleUsable::getTaskId, taskInfo.getTaskId()).list();
            list.forEach(o -> {
                o.setId(null);
                o.setTaskId(taskId);
            });
            ruleUsableService.saveBatch(list);

            //场地 教师
            List<RuleTimeProhibit> roomRule = baseMapper.getRoomRule(taskInfo.getTaskId(), ProhibitType.ROOM.getCode());
            Map<Integer, Long> roomMap = roomService.lambdaQuery().eq(Room::getTaskId, taskId).list()
                    .stream().collect(Collectors.toMap(Room::getBaseRoomId, Room::getRoomId));
            List<RuleTimeProhibit> roomSaveList = roomRule.stream().peek(o -> {
                        if (roomMap.containsKey(o.getBaseRoomId())) {
                            o.setTaskId(taskId);
                            o.setOptionId(roomMap.get(o.getBaseRoomId()));
                        }
                    }).filter(o -> o.getTaskId() != null)
                    .collect(Collectors.toList());
            if (CollUtil.isNotEmpty(roomSaveList)) {
                roomService.lambdaUpdate().eq(Room::getTaskId, taskId)
                        .set(Room::getRuleSet, 2).update();
                roomService.lambdaUpdate()
                        .eq(Room::getTaskId, taskId)
                        .in(Room::getRoomId, roomSaveList.stream().map(RuleTimeProhibit::getOptionId).distinct().collect(Collectors.toList()))
                        .set(Room::getRuleSet, 1).update();
            }

            List<RuleTimeProhibit> teacherRule = baseMapper.getTeacherRule(taskInfo.getTaskId(), ProhibitType.TEACHER.getCode());
            Map<String, Long> teacherMap = teacherService.lambdaQuery().eq(Teacher::getTaskId, taskId).list()
                    .stream().collect(Collectors.toMap(Teacher::getBaseTeacherId, Teacher::getTeacherId));
            List<RuleTimeProhibit> teacherSaveList = teacherRule.stream().peek(o -> {
                if (teacherMap.containsKey(o.getBaseTeacherId())) {
                    o.setTaskId(taskId);
                    o.setOptionId(teacherMap.get(o.getBaseTeacherId()));
                }
            }).filter(o -> o.getTaskId() != null).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(teacherSaveList)) {
                teacherService.lambdaUpdate().eq(Teacher::getTaskId, taskId).set(Teacher::getRuleSet, 2).update();
                teacherService.lambdaUpdate()
                        .eq(Teacher::getTaskId, taskId)
                        .in(Teacher::getTeacherId, teacherSaveList.stream().map(RuleTimeProhibit::getOptionId).distinct().collect(Collectors.toList()))
                        .set(Teacher::getRuleSet, 1).update();
                roomSaveList.addAll(teacherSaveList);
            }

            this.lambdaUpdate().eq(RuleTimeProhibit::getTaskId, taskId)
                    .notIn(RuleTimeProhibit::getOptionType, ProhibitType.TIME.getCode(),
                            ProhibitType.TEACHINGCLASS.getCode())
                    .remove();
            if (CollUtil.isNotEmpty(roomSaveList)) {
                baseMapper.addBatch(roomSaveList);
            }

            List<Course> courses = courseService.lambdaQuery()
                    .eq(Course::getTaskId, taskId)
                    .list();
            if (CollUtil.isNotEmpty(courses)) {
                List<String> baseCourseIds = courses.stream().map(Course::getBaseCourseId).distinct().collect(Collectors.toList());
                List<Course> preCourse = courseService.lambdaQuery()
                        .eq(Course::getTaskId, taskInfo.getTaskId())
                        .in(Course::getBaseCourseId, baseCourseIds)
                        .list();
                courseService.lambdaUpdate()
                        .eq(Course::getTaskId, taskId)
                        .set(Course::getCourseLimit, 0)
                        .update();
                courseService.copyCourseLimit(taskId, preCourse);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void synchronizeUpdate(Integer taskId) {
        List<Long> ids = teachingClassMapper.getAllTeachingClassId(taskId);
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        this.lambdaUpdate()
                .eq(RuleTimeProhibit::getOptionType, ProhibitType.TEACHINGCLASS.getCode())
                .eq(RuleTimeProhibit::getTaskId, taskId)
                .notIn(RuleTimeProhibit::getOptionId, ids)
                .remove();
        ids = roomMapper.getAllRoomId(taskId);
        this.lambdaUpdate()
                .eq(RuleTimeProhibit::getOptionType, ProhibitType.ROOM.getCode())
                .eq(RuleTimeProhibit::getTaskId, taskId)
                .notIn(RuleTimeProhibit::getOptionId, ids)
                .remove();
        ids = teacherMapper.getAllTeachierId(taskId);
        this.lambdaUpdate()
                .eq(RuleTimeProhibit::getOptionType, ProhibitType.TEACHER.getCode())
                .eq(RuleTimeProhibit::getTaskId, taskId)
                .notIn(RuleTimeProhibit::getOptionId, ids)
                .remove();

        scheduleService.synchronizeUpdate(null);
    }
}
